package com.example.demo.serivce.impl;

import com.example.demo.core.config.SipConfig;
import com.example.demo.core.util.MD5Util;
import com.example.demo.core.util.SipUtil;
import gov.nist.javax.sip.message.SIPRequest;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import javax.sip.*;
import javax.sip.address.SipURI;
import javax.sip.address.URI;
import javax.sip.header.*;
import javax.sip.message.MessageFactory;
import javax.sip.message.Request;
import javax.sip.message.Response;
import java.text.ParseException;
import java.util.Calendar;

@Service
@Slf4j
public class RegisterRequestHandler {
    @Resource
    SipFactory sipFactory;
    @Resource
    SipConfig sipConfig;
    @Resource
    ISIPCommanderImpl isipCommander;
    /**
     * TODO 注册和注销
     * @param requestEvent
     * @return
     * @throws SipException
     * @throws ParseException
     */
    public Response Register(RequestEvent requestEvent) throws SipException, ParseException {
        Request request = requestEvent.getRequest();
        AuthorizationHeader authorizationHeader = (AuthorizationHeader) request.getHeader(AuthorizationHeader.NAME);
        MessageFactory messageFactory = sipFactory.createMessageFactory();
        HeaderFactory headerFactory = sipFactory.createHeaderFactory();
        String deviceId = SipUtil.getDeviceId(request);
        Response response;
        //没有Authorization头,返回401
        if (authorizationHeader==null){
            CallIdHeader callIdHeader = (CallIdHeader) request.getHeader(CallIdHeader.NAME);
            String callId = callIdHeader.getCallId();
            response = messageFactory.createResponse(Response.UNAUTHORIZED, request);
            WWWAuthenticateHeader proxyAuthenticate = headerFactory
                    .createWWWAuthenticateHeader("Digest");
            proxyAuthenticate.setParameter("realm", sipConfig.getDomain());
            proxyAuthenticate.setParameter("qop", "auth");
            proxyAuthenticate.setParameter("nonce", MD5Util.MD5(callId + deviceId));
            proxyAuthenticate.setParameter("algorithm", "MD5");
            response.setHeader(proxyAuthenticate);
            log.info("[设备id] {},回复401", deviceId);
        }else if(isAuthorizationPass(request, sipConfig.getPassword())){
            ExpiresHeader expiresHeader = request.getExpires();
            if (expiresHeader == null) {
                response = messageFactory.createResponse(Response.BAD_REQUEST, request);
                return response;
            }else if (expiresHeader.getExpires()==3600){
                response = messageFactory.createResponse(Response.OK, request);
                DateHeader dateHeader = headerFactory.createDateHeader(Calendar.getInstance());
                response.addHeader(dateHeader);
                // 添加Contact头
                response.addHeader(request.getHeader(ContactHeader.NAME));
                // 添加Expires头
                response.addHeader(request.getExpires());
                log.info("[设备id]{},注册成功", deviceId);


                try {
                    isipCommander.deviceInfoQuery(requestEvent,deviceId,"gb2312");
                } catch (InvalidArgumentException e) {
                    throw new RuntimeException(e);
                }
            }else{
                response = messageFactory.createResponse(Response.OK, request);
                DateHeader dateHeader = headerFactory.createDateHeader(Calendar.getInstance());
                response.addHeader(dateHeader);
                // 添加Contact头
                response.addHeader(request.getHeader(ContactHeader.NAME));
                // 添加Expires头
                response.addHeader(request.getExpires());
                log.info("[设备id]{},注销成功", deviceId);
            }
        }else{
            response = messageFactory.createResponse(Response.FORBIDDEN, request);
            DateHeader dateHeader = headerFactory.createDateHeader(Calendar.getInstance());
            response.addHeader(dateHeader);
            log.info("[设备id]{},密码/SIP服务器ID错误,回复403", deviceId);
        }
        return response;
    }





    /**
     * 是否校验鉴权通过
     *
     * @param request
     * @return true 通过
     */
    private boolean isAuthorizationPass(Request request, String password) {
        AuthorizationHeader authorizationHeader = (AuthorizationHeader) request.getHeader(AuthorizationHeader.NAME);
        String username = authorizationHeader.getUsername();
        String realm = authorizationHeader.getRealm().trim();
        String nonce = authorizationHeader.getNonce().trim();
        URI uri = authorizationHeader.getURI();
        String res = authorizationHeader.getResponse();
        String algorithm = authorizationHeader.getAlgorithm();
        log.info("Authorization信息：username=" + username + ",realm=" + realm + ",nonce=" + nonce + ",uri=" + uri + ",response=" + res + ",algorithm=" + algorithm);
        if (null == username || null == realm || null == nonce || null == uri || null == res || null == algorithm) {
            log.error("Authorization信息不全，无法认证。");
            return false;
        } else {
            // 比较Authorization信息正确性
            String A1 = MD5Util.MD5(username + ":" + realm + ":" + password);
            String A2 = MD5Util.MD5("REGISTER".toUpperCase() + ":" + uri.toString());
            String cnonce = authorizationHeader.getCNonce();
            String qop = authorizationHeader.getQop();
            int nc = authorizationHeader.getNonceCount();
            String ncStr = String.format("%08x", nc).toUpperCase();
            String KD = A1 + ":" + nonce;
            if (qop != null && qop.equalsIgnoreCase("auth") ) {
                if (nc != -1) {
                    KD += ":" + ncStr;
                }
                if (cnonce != null) {
                    KD += ":" + cnonce;
                }
                KD += ":" + qop;
            }
            KD += ":" + A2;
            String resStr = MD5Util.MD5(KD);
            return resStr.equals(res);
        }
    }

}
